<?php

class Application_Plugin_Acl extends Zend_Controller_Plugin_Abstract {
	
	/**
	 * Obiectul ACL
	 * 
	 * @var Zend_Acl
	 **/
	protected $_acl;
	
	/**
	 * Numele rolului din care face parte userul
	 * 
	 * @var string
	 **/
	protected $_roleName;
	
	/**
	 * IDul identitatii din baza de date
	 *
	 * @var int
	 */
	protected $_idIdentity;
	
	const _USER_DEFAULT_GUEST = 'guest';
	
	/**
	 * Constructor
	 *
	 * @return void
	 **/
	public function __construct() {
		//include '../application/models/Users.php';
		//include 'Application/Modules/users/Models/AclRights.php';

	}
	
	public function dispatchLoopStartup() {
		$model_users = new Application_Model_Users();
		$model_acl_role = new Application_Model_AclRole();
		
		
		if (Zend_Auth::getInstance()->hasIdentity()) {
			$userArray = $model_users->getUserByField('`users`.id', Zend_Auth::getInstance()->getIdentity()->id);
			
			// Verificare de status pentru userul curent
			if ($userArray['status'] == 1) {
				$role = array_shift($model_acl_role->getRole(Zend_Auth::getInstance()->getIdentity()->acl_role_id));
				$this->_roleName = $role['name'];
			} else {
				$this->_roleName = self::_USER_DEFAULT_GUEST;
				Zend_Auth::getInstance()->clearIdentity();
			}
		} else 
			$this->_roleName = self::_USER_DEFAULT_GUEST;

		Zend_Registry::set('currentRoleName', $this->_roleName);
		
		$this->_populateAcl();
		if (defined('_USER_ALLOW_RESOURCES')) $this->_addAclException();
	}
	
	/**	
	 * Populeaza obiectul ACL
	 * In cazul in care se gaseste rolul stocat in cache se contruieste obiectul ACL cu ajutorul cachului
	 * Daca nu se va folosi baza de date pentru construirea obiectului ACL
	 *
	 * @param string $roleName
	 * @param Models_AlcRights $modelRights
	 * @return void
	 */
	protected function _populateAcl() {
		$cache = Zend_Registry::get('Zend_Cache_Core');
		if ( ($this->_acl = $cache->load('ACL_rights')) === false ){
			$this->_acl = new Zend_Acl();
			$modelAclRigths = new Application_Model_AclRights();
			$modelAclRole = new Application_Model_AclRole();
			$modelAclResources = new Application_Model_AclResources();

			$resources = $modelAclResources->getAclResources();
			foreach ( $resources as $resource ){
				$this->_acl->add( new Zend_Acl_Resource($resource['resource']) );
			}

			$roles = $modelAclRole->getAclRecurringRoles(0);
			foreach ( $roles as $role ){
				if ( $role['parent'] != '' ){
					$this->_acl->addRole( new Zend_Acl_Role($role['name']), $role['parent'] );
				}
				else{
					$this->_acl->addRole( new Zend_Acl_Role($role['name']) );
				}

				$rights = $modelAclRigths->getRightsForRoleId($role['id']);
				foreach ( $rights as $right ){
					if ( $right['permission'] ){
						$this->_acl->allow($role['name'], $right['resource']);
					}
					else{
						$this->_acl->deny($role['name'], $right['resource']);
					}
				}
			}
			$cache->save($this->_acl, 'ACL_rights');
		}

		Zend_Registry::set('acl', $this->_acl);
	}
	
	/**
	 * Adauga in obiectul de ACL exceptiile de acces definite in config.php 
	 *
	 * @param Zend_Controller_Request_Abstract $request
	 * @return void
	 */
	protected function _addAclException() {
		$aclExceptions = unserialize(_USER_ALLOW_RESOURCES);
		try {
			foreach ($aclExceptions as $aclException) {
				$aclException = str_replace('/',':',$aclException);
				// Se verifica daca exista deja in ACL
				if (!$this->_acl->has(new Zend_Acl_Resource($aclException))) { 
					$this->_acl->add(new Zend_Acl_Resource($aclException));
					$this->_acl->allow($this->_roleName, $aclException);
				}
			}
		} catch(Zend_Acl_Exception $e) {}
	}
	
	/**
	 * Seteaza obiectul ACL
	 *
	 * @param Zend_Acl $aclData
	 * @return void
	 **/
	public function setAcl(Zend_Acl $aclData) {
		$this->_acl = $aclData;
	}
	
	/**
	 * Intoarece obiectul ACL
	 *
	 * @return Zend_Acl
	 **/
	public function getAcl() {
		return $this->_acl;
	}
	
	/**
	 * Seteaza ce rol sa foloseasca obiectul ACL
	 *
	 * @param string $roleName
	 * @return none
	 **/
	public function setRoleName($roleName) {
		$this->_roleName = $roleName;
	}
	
	/**
	 * Intoarce ce rol exista in obiectul ACL
	 *
	 * @return string $roleName
	 **/
	public function getRoleName() {
		return $this->_roleName;
	}
	
	/**
	 * Predispatch
	 * Verifica daca requestul efectuat poate fi efectuat de rolul pe care il poseda userul
	 * In cazul in care nu are acces de executie se face forward la metoda deny()
	 *
	 * @param Zend_Controller_Request_Abstract $request
	 * @return void
	 **/
	public function preDispatch(Zend_Controller_Request_Abstract $request) {
		//Zend_Debug::dump($this->isRequestAllowed($request));
				//Zend_Debug::dump($request);die();
		if (!$this->isRequestAllowed($request)) {
			if($this->isLoginNeeded($request)) {
				$this->redirectToLogin();
			} else {
				$this->denyAccess($request);
			}
		}
	}
	
	/**
	 * Verifica daca un request este permis in rolul existent
	 *
	 * @param Zend_Controller_Request_Abstract $request
	 * @return boolean
	 */
	public function isRequestAllowed(Zend_Controller_Request_Abstract $request) {
		try {
			$module = $request->getModuleName();
			$controller = $request->getControllerName();
			$action = $request->getActionName();

//			Zend_Debug::dump($module . ':' . $controller . ':' . $action);
//			Zend_Debug::dump($this->_acl->has($module . ':' . $controller . ':' . $action));
//			Zend_Debug::dump($module . ':' . $controller);
//			Zend_Debug::dump($this->_acl->has($module . ':' . $controller));
//			Zend_Debug::dump($module);
//			Zend_Debug::dump($this->_acl->has($module));
//			Zend_Debug::dump($this->_acl);

			if ($this->_acl->has($module . ':' . $controller . ':' . $action)) {
//				Zend_Debug::dump($module . ':' . $controller . ':' . $action);
//				Zend_Debug::dump($this->_roleName);
//				Zend_Debug::dump($this->_acl->isAllowed($this->_roleName, $module . ':' . $controller . ':' . $action));
				if ($this->_acl->isAllowed($this->_roleName, $module . ':' . $controller . ':' . $action)) {
					return true;
				} else {
					return false; 
				}
			} else {
				if ($this->_acl->has($module . ':' . $controller)) {
//					Zend_Debug::dump($module . ':' . $controller);
//					Zend_Debug::dump($this->_acl->isAllowed($this->_roleName, $module . ':' . $controller));
					if ($this->_acl->isAllowed($this->_roleName, $module . ':' . $controller)) {
						return true;
					} else {
						return false;
					}
				} else {
					if ($this->_acl->has($module)) {
//						Zend_Debug::dump($module);
//						Zend_Debug::dump($this->_acl->isAllowed($this->_roleName, $module));
						if ($this->_acl->isAllowed($this->_roleName, $module)) {
							return true;
						} else {
							return false;
						}
					} else {
						// Nu are nimic din request in resurse ;)
						return false;
					}
				}
			}
		} catch (Zend_Acl_Exception $e) {
			return false;
		}
	}
	
	
	/**
	 * Redirectare la pagina de login / sau afisare mesaj de acces nepermis pentru partea de backend
	 *
	 * @return void
	 **/
	public function denyAccess(Zend_Controller_Request_Abstract $request) {
//		$redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
//		$redirector->gotoUrl('users');
		 $this->getResponse()->setRedirect('/');
	}
	
	public function isLoginNeeded(Zend_Controller_Request_Abstract $request) {
		return !Zend_Auth::getInstance()->hasIdentity();
	}
	
	/**
	 * Redirectare la pagina de login / sau afisare mesaj de acces nepermis pentru partea de backend
	 *
	 * @return void
	 **/
	public function redirectToLogin() {
//		$redirector = Zend_Controller_Action_HelperBroker::getStaticHelper('redirector');
//		$redirector->gotoUrl('auth/login');
		$this->getResponse()->setRedirect('auth/login');
	}
}